'use strict'

//切换工作目录(这样无论在哪里开启工作区，都会将工作区跳转到当前目录下)
process.chdir(__dirname);

const titbit=require('titbit');
const fs=require('fs');
const dbcfg=require('./dbconfig.js');  //引入数据库配置文件
const pg=require('pg');
const wxkey=require('./wxkey.js');
const {httpcli}=require('gohttp'); //封装了http请求模块的请求库，使用它里面的httpcli向微信服务器端发送请求获取openid
const token=require('titbit-token');  //使用它构造加密对象
const {cors} = require('titbit-toolkit');  //使用它来解决跨域问题
const tbloader=require('titbit-loader');

try{
    //检查该目录下是否存在images文件夹
    fs.accessSync('./images');
}catch(err){
    fs.mkdirSync('./images');
}

//创建一个连接池，连接池是服务器和数据库之间进行交互的桥梁
let psql=new pg.Pool(dbcfg);

let cert_path='/usr/local/share';

//new一个titbit对象时，就是执行了http.createServer()，开启一个服务
const app=new titbit({
    //开启测试模式，若有错误会输出错误信息
    debug:true,
    globalLog:true,  //开启全局日志
    cert:`${cert_path}/api.lzjlw.top.pem`,
    key:`${cert_path}/api.lzjlw.top.key`
})

let tb=new tbloader();
tb.init(app);
/* 
app.options('/admin/*', async c => {}, {group: '/admin'})
app.options('/user/*', async c => {}, {group: '/user'}) */

//在执行跨域请求中间件前会先发送一个options请求，该写法表示给所有url都添加上options路由
app.options('/*', async c => {})  

//app.service做资源的集中管理，初始为空对象,c.service就指向app.service
app.addService('psql',psql);  
//将这个连接池添加到app.service中，那么在content.js中就可以通过c.service.psql拿到psql进行使用
app.addService('imagePath',`${__dirname}/images`);
app.addService('wxkey',wxkey);
app.addService('httpcli',httpcli);


/* 注意：send函数只是设置ctx.res.body属性的值。
   和直接进行ctx.res.body赋值没有区别，只是因为函数调用如果出错会更快发现问题，
   而设置属性值写错了就是添加了一个新的属性，不会报错但是请求不会返回正确的数据。*/

/* ------------------------------------------------------------------------------------------------ */

let tok=new token({
    //token有效期，单位为秒
    expires: 3600, //加密后的数据生成后，只能在生成后的规定时限内进行解密，否则会超时造成解密失败
    //加解密的密钥，必须是32位字符
    key:'1234rdfvgt6yhu7ij7yhg8jngfruikng',
    //初始向量值，用于和最开始的数据块进行运算，必须是16位字符(该值最好是随机生成的)
    iv:'6tyghvui984rf7jy'
})

app.addService('tok', tok);

//该路由只用于进行解密结果展示
// app.get('/decrypt/:token',async c=>{
//     console.log(tok.verify(c.param.token)); //解密后的结果是对象，经过浏览器的处理后变成了json字符串
//     c.send(tok.verify(c.param.token));  //进行解密处理
// })
/* 结果示例：
    解密后的结果：{
        ok: true,
        data: {
            session_key: 'XR1WPWexFuQTFDSEEvgwZg==',
            openid: 'oJOXp5H4hKFGS-dPdekWIkJ_HtD8',
            expires: 45000,
            timestamp: 1634029825459,
            tokenId: ''
        },
        now: 1634029843614
    }
    呈现在浏览器上的结果：
    {"ok":true,"data":{"session_key":"S/NLzzciQ5zIByNlWrS2sA==","openid":"oJOXp5H4hKFGS-dPdekWIkJ_HtD8",
    "expires":45000,"timestamp":1633941628402,"tokenId":""},"now":1633941638241} */


/* 文件对象
{
    filename,   原始文件名
    'content-type',   文件类型
    start,   ctx.rawBody开始的索引位置
    end,   ctx.rawBody结束的索引位置   
    length,   文件长度，字节数
    rawHeader   原始消息头文本，是multipart/form-data的消息头
}
*/

/**HTTP消息头的content-type指定了数据的类型(数据的格式)
   Client                                               Server
   content-type描述的值要和提交的body数据的格式一致       根据content-type的值决定如何解析body数据
   content-type:
   multipart/form-data;boundary=xxx   -------------    文件解析
   text/*          --------------------------------    文本类型
   application/*   --------------------------------    要看具体值，application/json也是文本类型
   .......         --------------------------------    每种类型如何处理是双方设计好的通信方式
   到web框架这一层面，该如何处理是开发框架设计好的，但通常都要遵循一个原则：允许开发者做自己的处理
   在本框架范围内：
   multipart类型 --- c.body是object类型，文件信息解析到c.files
   application/x-www-form-urlencoded  传统的表单类型 --- c.body是object类型，用于获取提交的表单数据
   text/* --- c.body 是文本类型，c.body = c.rawBody.toString('utf8')
   其他类型： c.body 是buffer类型，就是对c.rawBody的引用
 */

//运行在3456端口
app.run(3456)
